#include "stdafx.h"
#include "QMainFrame.h"
#include "XmlGame.h"
#include "TextureLoader.h"

XmlGame::XmlGame(int numUtils)
	: Game(numUtils), numUtils(numUtils)
{
	// Set some built-in options.
	AddOption(wxT("DefaultPalette"), &palDef);
	AddOption(wxT("DefaultTexture"), &defTexture);
	AddOption(wxT("TextureExtension"), &texExt);
	AddOption(wxT("GameDir"), &gameDir);
	SetOption(wxT("InitDir"), LFile::GetInitDir());
	nearPlane = 1.0f;
	farPlane = 1000.0f;
	exportWad = false;
	textureLoader = NULL;
}

XmlGame::~XmlGame()
{
	cfg->SaveVars();
	delete cfg;

	// Free the dynamic options.
	for(size_t i = 0; i < dynamicOptions.size(); i++)
		delete dynamicOptions[i];

	delete textureLoader;
}

void XmlGame::BuildConfig()
{
	cfg = new LConfig(gameName);

	// Built-in functions.
	setPIndex = 0;
	cfg->RegisterVar(wxT("SetParamIndex"), &setPIndex, LVAR_INT);

	runUtilsFlag = 0x0001;
	cfg->RegisterVar(wxT("RunUtils"), &runUtilsFlag, LVAR_INT);

	// Register the options.
	Options::iterator it = options.begin();
	for(; it != options.end(); it++)
	{
		cfg->RegisterVar(it->first, it->second, LVAR_WXSTR);
	}

	// Register the utilities.
	for(int i = 0; i < numUtils; i++)
	{
		cfg->RegisterVar(wxString::Format(wxT("UtilPath%d"), i+1),
				&utilsPath[i], LVAR_WXSTR);
		cfg->RegisterVar(wxString::Format(wxT("UtilParam%d"), i+1), &utilsParams[i],
				LVAR_WXSTR);
	}
}

bool XmlGame::Init(void)
{
	if(initialized)
		return true;

	if(gameDir.empty() || !LFile::ExistDir(gameDir))
	{
		wxDirDialog dlg(GetMainFrame(),
				wxString::Format(_("Locate %s Folder"), gameName.c_str()));

		if(dlg.ShowModal() != wxID_OK)
			return false;

		gameDir = dlg.GetPath();
	}

	baseDir = GetOption(wxT("BaseDir"));
	mapDir = GetOption(wxT("MapDir"));
	texDir = GetOption(wxT("TexDir"));
	wxString defGridSize = GetOption(wxT("DefaultGridSize"), wxT("16"));
	wxString defRotSnapSize = GetOption(wxT("DefaultRotSnapSize"), wxT("15"));
	wxString gridStepBase = GetOption(wxT("GridBase"), wxT("2"));
	wxString gridStepFactor = GetOption(wxT("GridSteps"), wxT("4"));
	wxString nearPlaneValue= GetOption(wxT("NearPlane"), wxT("1"));
	wxString farPlaneValue= GetOption(wxT("FarPlane"), wxT("1000"));
	ReplaceVars2(baseDir);
	ReplaceVars2(mapDir);
	ReplaceVars2(texDir);
	ReplaceVars2(defGridSize);
	ReplaceVars2(defRotSnapSize);
	ReplaceVars2(gridStepBase);
	ReplaceVars2(gridStepFactor);

	// Read the map grid parameters.
	defaultGridSize = atoi(defGridSize.utf8_str());
	defaultRotSnapSize = atoi(defRotSnapSize.utf8_str());
	gridBase = atoi(gridStepBase.utf8_str());
	gridSteps = atoi(gridStepFactor.utf8_str());
	nearPlane = atof(nearPlaneValue.utf8_str());
	farPlane = atof(farPlaneValue.utf8_str());

	// Read the primitives set.
	primitivesSet = GetOption(wxT("PrimitivesSet"), wxT("brushes/imperial.xml"));

	// Read the compile map format.
	mapExt = GetOption(wxT("MapFormat"));
	if(mapExt.empty())
		mapExt = wxT("map");

	qualifiedTextures = GetOption(wxT("QualifiedTexture")).CmpNoCase(wxT("false"));

	textureLoader = TextureLoader::CreateLoader(GetOption(wxT("TextureLoader")));

	texDB = new TexDB(this);
	texDB->AddTexDir(texDir);

	initialized = true;

	LFile::UseDir(baseDir);
	return true;
}

WireFrameGeom *XmlGame::LoadModel(const wxString &filename)
{
	return NULL;
}

bool XmlGame::LoadTexture(Texture *texture, const wxString &filename, int offset)
{
	if(textureLoader)
		return textureLoader->LoadTexture(texture, filename, offset);
	return false;
}

int XmlGame::GetDefaultGridSize() const
{
	return defaultGridSize;
}

int XmlGame::GetDefaultRotSnapSize() const
{
	return defaultRotSnapSize;
}

int XmlGame::GetGridSteps() const
{
	return gridSteps;
}

int XmlGame::GetGridSizeBase() const
{
	return gridBase;
}

float XmlGame::GetNearPlane() const
{
	return nearPlane;
}

float XmlGame::GetFarPlane() const
{
	return farPlane;
}

int XmlGame::GetNumGameSets()
{
	return gameSets.size();
}

const wxString &XmlGame::GetPrimitivesSet() const
{
	return primitivesSet;
}

void XmlGame::GetGameSet(int index, wxString &name, wxString &entName, wxString &palName)
{
	ASSERT(index >= 0 && index < gameSets.size());

	GameSet &set = gameSets[index];
	name = set.name;
	entName = set.entName;
	palName = set.palName;
}

int XmlGame::GetNumUtils(void) const
{
	return numUtils;
}

const wxString &XmlGame::GetUtilName(int index) const
{
	ASSERT(index >= 0 && index < numUtils);
	return utilNames[index];
}

bool XmlGame::GetUtilCmdLine(int utilIndex, const wxString &docName,
							wxString *cmdLine, wxString *initDir,
							OutTextProc pTextProc) const
{
	ASSERT(!docName.empty());
	ASSERT(cmdLine);
	ASSERT(initDir);

	int numUtils = GetNumUtils();

	if (utilIndex < 0 || utilIndex >= numUtils)
		return false;

	cmdLine->Printf(wxT("%s %s"), utilsPath[utilIndex].c_str(),
			utilsParams[utilIndex].c_str());
	cmdLine->Replace(wxT("%file%"), docName.c_str());
	cmdLine->Replace(wxT("%FILE%"), docName.c_str());
	ReplaceVars(*cmdLine);

#ifndef _WIN32
	// Run through wine windows programs.
	if(wxFileName(utilsPath[utilIndex]).GetExt().CmpNoCase(wxT("exe")) == 0)
		*cmdLine = wxT("wine ") + *cmdLine;
#endif

	// InitDir
	if (utilIndex != numUtils - 1)
		*initDir = mapDir;
	else
		*initDir = gameDir;

	return true;
}


void XmlGame::ReplaceVars(wxString &string) const
{
	Options::const_iterator it = options.begin();
	for(; it != options.end(); it++)
	{
		string.Replace(wxString::Format(wxT("%%%s%%"), it->first.c_str()),
				*it->second);
	}
}

const wxString &XmlGame::GetOption(const wxString &name, const wxString &def) const
{
	Options::const_iterator it = options.find(name);
	if(it != options.end())
		return *it->second;

	return def;
}

void XmlGame::SetOption(const wxString &name, const wxString &value)
{
	Options::const_iterator it = options.find(name);
	if(it != options.end())
		*it->second = value;
	else
	{
		wxString *dynValue = new wxString(value);
		options.insert(std::make_pair(name, dynValue));
		dynamicOptions.push_back(dynValue);
	}
}

void XmlGame::AddOption(const wxString &name, wxString *value)
{
	options.insert(std::make_pair(name, value));
}

XmlGame *XmlGame::LoadGame(const wxString &filename)
{
	// Load the document.
	wxXmlDocument doc;
	if(!doc.Load(filename))
		return NULL;

	// Get the root node.
	wxXmlNode *root = doc.GetRoot();
	if(root->GetName() != wxT("qgame"))
		return NULL;

	// Get the game name.
	wxString name = root->GetAttribute(wxT("name"), wxT(""));

	// Check the game name.
	if(name.empty())
		return NULL;

	// Find the interesting nodes.
	wxXmlNode *options = NULL;
	wxXmlNode *utilities = NULL;
	wxXmlNode *gameSets = NULL;
	wxXmlNode *child = root->GetChildren();
	for(; child; child = child->GetNext())
	{
		if(child->GetName() == wxT("options"))
			options = child;
		else if(child->GetName() == wxT("utilities"))
			utilities = child;
		else if(child->GetName() == wxT("gameSets"))
			gameSets = child;
	}

	// Check the presence of the options and utilities nodes.
	if(!options || !utilities)
		return NULL;

	// Read the number of utils.
	long numUtils = 0;
	if(!utilities->GetAttribute(wxT("numUtils"), wxT("")).ToLong(&numUtils))
		return NULL;

	// Create the game.
	XmlGame *game = new XmlGame(numUtils);
	game->gameName = name;

	// Read the options.
	wxXmlNode *option = options->GetChildren();
	for(; option; option = option->GetNext())
	{
		if(option->GetName() != wxT("option"))
			continue;

		wxString key = option->GetAttribute(wxT("name"), wxT(""));
		if(key.empty())
			continue;

		wxString value = option->GetAttribute(wxT("value"), wxT(""));

		// Store the option.
		game->SetOption(key, value);
	}

	// Read the utilities
	wxXmlNode *util = utilities->GetChildren();
	int i = 0;
	for(; util; util = util->GetNext())
	{
		if(util->GetName() != wxT("util"))
			continue;

		wxString name = util->GetAttribute(wxT("name"), wxT(""));
		if(name.empty())
			continue;

		wxString defaultPath = util->GetAttribute(wxT("defaultPath"), wxT(""));
		wxXmlNode *params = util->GetChildren();
		for(; params; params = params->GetNext())
			if(params->GetName() == wxT("params"))
				break;

		game->utilNames.push_back(name);
		game->utilsPath.push_back(defaultPath);
		if(params)
			game->utilsParams.push_back(params->GetNodeContent());
		else
			game->utilsParams.push_back(wxEmptyString);

		// Increase the utility index.
		i++;
	}

	// Read the optional game sets section.
	if(gameSets)
	{
		wxXmlNode *gameSet = gameSets->GetChildren();
		for(; gameSet; gameSet = gameSet->GetNext())
		{
			if(gameSet->GetName() != wxT("gameSet"))
				continue;

			GameSet data;
			data.name = gameSet->GetAttribute(wxT("name"), wxT(""));
			data.entName = gameSet->GetAttribute(wxT("entName"), wxT(""));
			data.palName = gameSet->GetAttribute(wxT("palName"), wxT(""));

			if(data.name.empty() || data.entName.empty())
				continue;

			game->gameSets.push_back(data);
		}
	}
	// Build the game configuration.
	game->BuildConfig();

	return game;
}

void XmlGame::LoadGames()
{
	LFindFiles xmlFiles(LFile::GetInitDir() + wxT("/games"), wxT("*.xml"));
	wxString file = xmlFiles.Next();
	for(; !file.empty(); file = xmlFiles.Next())
		LoadGame(file); // Yes, ignore the return value.
}
